import { ChildProcessWithoutNullStreams, spawn } from "child_process";
import path from "path";
import { exists, isFile } from "./file";
import fs from "fs/promises";
import kill from "tree-kill";
import net from "net";

const mysqlBase = path.resolve(__dirname, "../mysql/mysql-8.4.6-winx64");
const mysqlBin = path.join(mysqlBase, "bin", "mysqld.exe");
const dataDir = path.join(mysqlBase, "data");
export const pidFile = path.join(__dirname, "mysql.pid");
const mysqlArgs = [`--datadir=${dataDir}`, "--port=3306"];
let mysqlProcess: ChildProcessWithoutNullStreams | null = null;

export async function removePidFile() {
  const status = await isFile(pidFile);
  if (status) {
    await fs.unlink(pidFile);
  }
}

export async function isPortUsed(
  port: number,
  host = "127.0.0.1"
): Promise<boolean> {
  return new Promise((resolve) => {
    const socket = new net.Socket();

    socket.setTimeout(1000); // 1秒超时

    socket.on("connect", () => {
      socket.destroy();
      resolve(true); // 能连接 -> 被占用
    });

    socket.on("timeout", () => {
      socket.destroy();
      resolve(false);
    });

    socket.on("error", () => {
      resolve(false); // 连接错误 -> 端口没被占用
    });

    socket.connect(port, host);
  });
}

export async function startMySQL() {
  const portUsed = await isPortUsed(3306);
  if (portUsed) {
    console.error("[MySQL] 端口 3306 已被占用，请先释放端口或修改配置！");
    return;
  }

  if (mysqlProcess) {
    console.log(`[MySQL] 已经在运行`);
    return;
  }

  const isExists = await exists(dataDir);
  if (!isExists) {
    console.log("[MySQL] 初始化数据目录...");
    await fs.mkdir(dataDir, { recursive: true });
    // "--initialize-insecure" ---> 空密码初始化
    // "--initialize" ---> 随机密码初始化
    // 初次登录mysql需要执行SQL： set password for root@localhost=password("你的密码") 重新设置密码，才不会错误1820（HY000）
    mysqlArgs.unshift("--initialize-insecure");
  }

  console.log(`[MySQL] 正在启动... ${pidFile}`);

  mysqlProcess = spawn(mysqlBin, mysqlArgs, {
    detached: true, // 脱离当前进程
    // stdio: "ignore", // 不继承控制台输出
    stdio: ["ignore", "pipe", "pipe"], // 输入忽略，输出/错误可读
    // stdio: "inherit", // 继承控制台输出
    windowsHide: true, // 关键参数，隐藏CMD窗口
  });

  mysqlProcess.stdout.on("data", (chunk) => {
    process.stdout.write(`[MySQL stdout] ${chunk}`);
  });

  mysqlProcess.stderr.on("data", (chunk) => {
    process.stderr.write(`[MySQL stderr] ${chunk}`);
  });

  mysqlProcess.on("error", (err) => {
    console.error(`[MySQL] 启动失败`, err);
    mysqlProcess = null;
  });

  mysqlProcess.on("close", (code, signal) => {
    removePidFile().then(() => {
      console.log(`[MySQL] 退出，code=${code} signal=${signal}`);
      mysqlProcess = null;
    });
  });

  // 把 PID 存到文件
  await fs.writeFile(pidFile, mysqlProcess.pid.toString(), "utf-8");

  // 让子进程独立运行
  mysqlProcess.unref();

  console.log(`[MySQL] 已后台启动，PID=${mysqlProcess.pid}`);
}

export async function stopMySQL() {
  const isExists = await isFile(pidFile);
  if (!isExists) {
    console.log("[MySQL] 没有找到 PID 文件");
    return;
  }

  const pid = await fs.readFile(pidFile, "utf-8");
  console.log(`[MySQL] 尝试结束进程 PID=${pid}`);

  // tree-kill 跨平台安全杀掉进程树
  return new Promise<void>((resolve, reject) => {
    kill(+pid, "SIGTERM", (err) => {
      if (err) {
        console.error(`[MySQL] 停止失败`, err);
        reject(err);
      } else {
        console.log(`[MySQL] 已停止`);
        removePidFile().then(resolve);
      }
    });
  });
}

export async function restartMySQL() {
  console.log(`[MySQL] 正在重启...`);
  try {
    await stopMySQL();
    await startMySQL();
  } catch {}
}

export async function statusTextMySQL() {
  const mysql = await isFile(pidFile);
  return mysql ? "(已开启)" : "(已停止)";
}
